
#include  "my_printf.h"


//==================================================================================================
typedef char *  va_list;
#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )
//#define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_arg(ap,t)    ( *(t *)( ap=ap + _INTSIZEOF(t), ap- _INTSIZEOF(t)) )
#define va_end(ap)      ( ap = (va_list)0 )

//==================================================================================================
unsigned char hex_tab[]={'0','1','2','3','4','5','6','7',\
    '8','9','a','b','c','d','e','f'};
    
    static int outc(int c) 
{
    __out_putchar(c);
	return 0;
}

static int outs (const char *s)
{
    while (*s != '\0')	
	__out_putchar(*s++);
	    return 0;
}

static int out_num(long n, int base,char lead,int maxwidth) 
{
    unsigned long m=0;
	char buf[MAX_NUMBER_BYTES], *s = buf + sizeof(buf);
	int count=0,i=0;
	
	
	*--s = '\0';
	
	if (n < 0){
	    m = -n;
	}
	else{
	    m = n;
	}
    
	do{
	    *--s = hex_tab[m%base];
		count++;
	}while ((m /= base) != 0);
    
	if( maxwidth && count < maxwidth){
	    for (i=maxwidth - count; i; i--)	
		*--s = lead;
	}
    
	if (n < 0)
	    *--s = '-';
		
		return outs(s);
}


/*reference :   int vprintf(const char *format, va_list ap); */
static int my_vprintf(const char *fmt, va_list ap) 
{
    char lead=' ';
	int  maxwidth=0;
	
	for(; *fmt != '\0'; fmt++)
	{
	    if (*fmt != '%') {
		outc(*fmt);
		    continue;
	    }
	    
		//format : %08d, %8d,%d,%u,%x,%f,%c,%s 
		fmt++;
		if(*fmt == '0'){
		    lead = '0';
			fmt++;	
		}
	    
		lead=' ';
		maxwidth=0;
		
		while(*fmt >= '0' && *fmt <= '9'){
		    maxwidth *=10;
			maxwidth += (*fmt - '0');
			fmt++;
		}
	    
		switch (*fmt) {
		    case 'd': out_num(va_arg(ap, int),          10,lead,maxwidth); break;
		    case 'o': out_num(va_arg(ap, unsigned int),  8,lead,maxwidth); break;				
		    case 'u': out_num(va_arg(ap, unsigned int), 10,lead,maxwidth); break;
		    case 'x': out_num(va_arg(ap, unsigned int), 16,lead,maxwidth); break;
		    case 'c': outc(va_arg(ap, int   )); break;		
		    case 's': outs(va_arg(ap, char *)); break;		  		
			      
		    default:  
			      outc(*fmt);
				  break;
		}
	}
    return 0;
}


//reference :  int printf(const char *format, ...); 
int printf(const char *fmt, ...) 
{
    va_list ap;

	va_start(ap, fmt);
	my_vprintf(fmt, ap);	
	va_end(ap);
	return 0;
}


int my_printf_test(void)
{
    printf("This is www.100ask.org   my_printf test\n\r") ;	
	printf("test char           =%c,%c\n\r", 'A','a') ;	
	printf("test decimal number =%d\n\r",    123456) ;
	printf("test decimal number =%d\n\r",    -123456) ;	
	printf("test hex     number =0x%x\n\r",  0x55aa55aa) ;	
	printf("test string         =%s\n\r",    "www.100ask.org") ;	
	printf("num=%08d\n\r",   12345);
	printf("num=%8d\n\r",    12345);
	printf("num=0x%08x\n\r", 0x12345);
	printf("num=0x%8x\n\r",  0x12345);
	printf("num=0x%02x\n\r", 0x1);
	printf("num=0x%2x\n\r",  0x1);
	
	printf("num=%05d\n\r", 0x1);
	printf("num=%5d\n\r",  0x1);
	
	return 0;
}



